#include "sm2.h"
#include "sm2_operation.h"
#include "sm2_ec.h"
#include "sm2_rand.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>

#define WIN32_BCrypt

#ifdef WIN32_BCrypt
#include <windows.h>
#include <wincrypt.h>
#pragma comment(lib, "bcrypt.lib")
#endif

extern const SM2_Jacobian_Point SM2_G;
extern const sm2_uint256_t ZERO;
extern const sm2_uint256_t ONE;
extern const sm2_uint256_t SM2_P;
extern const sm2_uint256_t SM2_A;
extern const sm2_uint256_t SM2_B;
extern const sm2_uint256_t SM2_N;
extern const sm2_uint512_t SM2_Ps[13];
extern const sm2_uint512_t SM2_P_sqr;
extern const sm2_uint256_t Gx;
extern const sm2_uint256_t Gy;
extern const sm2_uint256_t SM2_N_MINUS_ONE;

int sm2_key_print(FILE *fp, int fmt, int ind, const char *label, const SM2_Key *key)
{
	ind += 4;
	sm2_print(fp, fmt, ind, "privateKey", key->private_key);
	// sm2_public_key_print(fp, fmt, ind, "publicKey", key-);
	return 1;
}

int rand_bytes(uint8_t *buf, size_t len)
{
	if (!buf)
	{
		printf("缓冲区空 error\n");
		return -1;
	}
	#ifdef WIN32_BCrypt
	if (len > INT_MAX)
	{
		printf("溢出 error\n");
		return -1;
	}
	NTSTATUS status = BCryptGenRandom(NULL, buf, (ULONG)len, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
	if (status != 0)
	{
		printf("生成指定长度的随机字节 error\n");
		return -1;
	}
	#endif
	#ifdef UNIX
	FILE *fp;

	if(!(fp = fopen("/dev/random", "rb"))){
		fprintf(stderr, "打开/dev/random失败\n");
		return -1;
	}
	if(fread(buf, 1, len, fp) != len){
		fprintf(stderr, "读取随机数失败\n");
		fclose(fp);
		return -1;
	}
	fclose(fp);
	#endif

	return 1;
}

// 随机数
int sm2_rand_range(sm2_uint256_t r, const sm2_uint256_t range)
{
	unsigned int count = 100;
	do
	{
		if (!count)
		{
			return 0;
		}
		if (rand_bytes((uint8_t *)r, 32) != 1)
		{
			printf("生成随机数 error");
			return -1;
		}
		count--;
	} while (sm2_compare(r, range) < SM2_COMPARE_LT);
	return 1;
}

int sm2_key_generate(SM2_Key *key)
{
	if (!key)
	{
		printf("key error");
		return -1;
	}
	// 随机生成私钥 private_key
	do
	{
		if (sm2_rand_range(key->private_key, SM2_N_MINUS_ONE) != 1)
		{
			printf("生成私钥 error");
			return -1;
		}
	} while (sm2_compare(key->private_key, ZERO) == SM2_COMPARE_EQ);
	SM2_Jacobian_Point G_jacobian, pub, tmp;
	sm2_set_jacobian_point(&G_jacobian, Gx, Gy);
	sm2_jacobian_point_k_mul(&tmp, &G_jacobian, key->private_key);
    sm2_get_affine_point(&pub, &tmp);
    sm2_copy(key->public_key.x, pub.x);
    sm2_copy(key->public_key.y, pub.y);
	return 1;
}
